﻿using System;
using System.ComponentModel;
using System.Drawing;
using System.Drawing.Drawing2D;

namespace Core
{

    public enum TypeOfLink
    {
        [Description("Передача сообщения")]
        Message,
        [Description("Условная передача управления")]
        Condition,
        [Description("Сообщение самому себе")]
        Ativate
    }

    public class Link:IGraphElement
    {
        #region Поля
        [DisplayName("Id")]
        [Description("Поле Id")]
        [Category("1. Данные")]
        public String Id { get; set; }
        //public String Id { get; set; }
        [Browsable(false)]
        public String Module { get; set; }
        [Browsable(false)]
        public Node _next { get; set; }
        [Browsable(false)]
        public int Value { get; private set; }
        [Category("2. Положение")]
        public int X { get; set; }
        [Category("2. Положение")]
        public int Y { get; set; }
        [DisplayName("Тип связи")]
        [Description("Поле Id")]
        [Category("1. Данные")]
        public TypeOfLink TOfLink { get; set; }
        [Browsable(false)]
        public bool IsSelected { get; set; }
        private Node _nodefrom;
        private Graph.TypeOfGraph _typeOfGraph;

        #endregion

        public Link (Node nodeto,Node nodefrom,TypeOfLink typeoflink,String label, Graph.TypeOfGraph typeOfGraph)
        {
            Id = "";
            Id = label;
            _typeOfGraph = typeOfGraph;
            _nodefrom = nodefrom;
            _next = nodeto;
            Value = nodefrom.GetPryoryty(); 
            X = (_next.X + nodefrom.X) / 2;
            Y = (_next.Y + nodefrom.Y) / 2;
            TOfLink = typeoflink;
            IsSelected = false;
        }

        public void Replace()
        {
            X = (_next.X + _nodefrom.X) / 2;
            Y = (_next.Y + _nodefrom.Y) / 2;
        }

        public void DrawLink(Graphics graphics, Node node)
        {
            var pen = new Pen(Color.Blue);
            if(TOfLink == TypeOfLink.Message)
            {
                float[] ptrn = new float[] { 4.0F, 4.0F, 4.0F, 4.0F };
                pen.DashPattern = ptrn;
            }
            pen.Width = (float) 1.5;
            int r = 1;
            float k = 0;
            int cx = 0;
            int cy = 0;
            if(Y == _next.Y)
            {
                cx = Math.Sign(X - _next.X) * 15;
                cy = 0;
            }
            else
            {
                if (X != _next.X)
                {
                    k = ((float)(Y - _next.Y)) / (X - _next.X);
                    double a = Math.Atan(k);
                    r = Math.Sign(Y - _next.Y);

                    if ((a > 0) && (a < Math.PI))
                    {
                        cx = (int)Math.Round(r * 15 * Math.Cos(a));
                        cy = (int)Math.Round(r * 15 * Math.Sin(a));
                    }
                    else
                    {
                        cx = (int)Math.Round(-r * 15 * Math.Cos(a));
                        cy = (int)Math.Round(-r * 15 * Math.Sin(a));
                    }
                }
                else
                {
                    cx = 0;
                    cy = Math.Sign(Y - _next.Y) * 15;

                }
            }
            
            Font drawFont = new Font("Arial", 12);
            graphics.DrawLine(pen, node.X, node.Y, X, Y);
            Line1(graphics, pen, X, Y,cx+_next.X, cy+_next.Y, 25, 5);
            SolidBrush drawRectB = new SolidBrush(Color.White);
            SolidBrush drawBrush = new SolidBrush(Color.Black);
            RectangleF drawRect = new RectangleF(X-10, Y-10, 20, 20);
            graphics.DrawRectangle(new Pen(Color.Blue), X-10,Y-10,20,20);
            graphics.FillRectangle(drawRectB, X - 9, Y - 9, 18, 18);
            graphics.DrawString(Value.ToString(), drawFont,drawBrush,drawRect);
            graphics.DrawString(Id, drawFont, drawBrush, new RectangleF(X-10*Id.Length/2,Y-40,Id.Length*15,20));

        }

        static void Line1(Graphics graphics,Pen pen,float x1, float y1, float x2, float y2,float s, float s1)
        {
            float a,b,x3 = 0,y3 = 0,x4 = 0,y4=0,x5=0,y5=0,al=0,a1=0,b1=0;
            PointF[] points = new PointF[5];
            SolidBrush drawBrush = new SolidBrush(Color.Blue);
            //если горизонтальная или вертикальная линия
            if((x1==x2)||(y1==y2))
            {
                
                if(x1==x2)
                {
                    if(y1>y2) {x3=x1; y3=y2+s;};
                    if(y2>y1) {x3=x1; y3=y2-s;};
                    y4=y3; y5=y3;
                    x4=x3-(s1/2); x5=x3+(s1/2);
                };
                if(y1==y2)
                {
                    if(x1>x2) {y3=y1; x3=x2+s;};
                    if(x2>x1) {y3=y1; x3=x2-s;};
                    x4=x3; x5=x3;
                    y4=y3-(s1/2); y5=y3+(s1/2);
                };
               
                graphics.DrawLine(pen,x1,y1,x2,y2);
               // graphics.FillPolygon(drawBrush, points,FillMode.Winding);
                return;
            }
            //найдем x3,y3
            a=y2-y1; b=x2-x1;
            if(b==0) {al=(float) 3.14;} else {al=(float) Math.Atan(a/b);}
            int kof1=1;
            a1=(float) (s*Math.Sin(al)); b1=(float) (s*Math.Cos(al));
            if (b>0) {kof1=-1;} else {kof1=1;};
            x3=x2+kof1*b1; y3=y2+kof1*a1;
            //находим x4,y4,x5,y5
            //уравнение прямой: A*x+B*y+C=0
            //где A=y2-y1; B=x1-x2; C=x1*y2-x2*y1;
            //Уравнение перпендикуляра из точки (x3,y3) B*x-A*y+C2=0
            //где C2=A*y3-B*x3;
            float A,B,C2;
            A=y2-y1; B=x1-x2; C2=(float) (A*y3-B*x3);
            float y11,y22;
            if (A!=0) {y11=(B*x1+C2)/A; y22=(B*x2+C2)/A;}
            else {y11=0; y22=0;}
            a=y22-y11; b=x2-x1; s1=s1/2;
            if(b==0) {al=(float) 3.14;} else {al=(float) Math.Atan(a/b);};
            a1=(float) (s1*Math.Sin(al)); b1=(float) (s1*Math.Cos(al));
            x4=(float) (x3+b1); y4=(float) (y3+a1); x5=(float) (x3-b1); y5=(float) (y3-a1);
            points[0] = new PointF(x3,y3);
            points[1] = new PointF(x4,y4);
            points[2] = new PointF(x2,y2);
            points[3] = new PointF(x5,y5);
            points[4] = new PointF(x3,y3);
            graphics.DrawLine(pen,x1,y1,x3,y3);
            graphics.DrawClosedCurve(new Pen(Color.Blue), points, 0.0f, FillMode.Winding);
            //теперь рисуем
            /*TPoint points[]={ Point(x1,y1), Point(x3,y3),
                Point(x4,y4), Point(x2,y2), Point(x5,y5),
                Point(x3,y3)};
            imag1->Canvas->Pen->Color=clBlack;
            imag1->Canvas->Brush->Color=clBlack;
            imag1->Canvas->Polygon(points, 5);
            imag1->Canvas->Brush->Color=clWhite;*/
            return;
        }

        public override string ToString()
        {
            string result = "";
            string temp = "";
            if (_typeOfGraph ==Graph.TypeOfGraph.Process)
            {
                switch (_nodefrom.Nodetype)
                {
                    case TypeOfNode.Method:
                        {
                            temp = "send ";
                            break;
                        }
                    default:
                        {
                            temp = "receive ";
                            break;
                        }
                }
            }
            else
            {
                temp = "message ";
            }
            result += '<' + temp + "id=" + '"' + Id + '"';
            switch (_next.Nodetype)
            {
                case TypeOfNode.Method:
                    {
                        temp = " method";
                        break;
                    }
                default:
                    {
                        temp = " port";
                        break;
                    }
            }
            if (_typeOfGraph == Graph.TypeOfGraph.Chenal)
            {
                temp = " state";
            }
            result += temp + '=' + '"' + _next.Id + '"' + " x=" + '"' + X + '"' + " y=" + '"' + Y + '"' + " rem=" +
                      '"' + '"' + "/>" + "\r\n";
            //result+= "<connector state=";
            //result += '"';
            //switch (_typeoflink)
            //{
            //    case 0:
            //        {
            //            result += "continue"; 
            //            break;
            //        }
            //    case 1:
            //        {
            //            result += "if"; 
            //            break;
            //        }
            //    case 2:
            //        {
            //            result += "new";
            //            break;
            //        }
            //}
            //result += '"';result += " label=";result += '"';
            //result += _next.Id;result += '"';result += " id=";
            //result += '"';result += Id;result += '"';
            //result += " module=";result += '"';result += Module;
            //result += '"';result += " x=";result += '"';
            //result += X.ToString();result += '"';result += " y=";
            //result += '"';result += Y.ToString();result += '"';result += "/>";
            return result;
        }
        
    }
}
